using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Runtime.InteropServices;
using AOT;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;

#if UNITY_WEBGL
namespace JSDBV2
{
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void strPointerCallback(int pointer, string value);

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void intPointerCallback(int pointer, int value);

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void floatPointerCallback(int pointer, float value);

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void floatArrayPointerCallback(int pointer, IntPtr unit8ArrayPointer, int length);

    public class IndexedDB
    {
        [DllImport("__Internal")]
        public static extern void initJsStringToBuffer_v2();

        [DllImport("__Internal")]
        public static extern void dbAddData_v2(int pointer, string key, string content,
            [MarshalAs(UnmanagedType.FunctionPtr)] strPointerCallback result = null);

        [DllImport("__Internal")]
        public static extern void dbAddDataInt_v2(int pointer, string key, int content,
            [MarshalAs(UnmanagedType.FunctionPtr)] strPointerCallback result = null);

        [DllImport("__Internal")]
        public static extern void dbAddDataFloat_v2(int pointer, string key, float content,
            [MarshalAs(UnmanagedType.FunctionPtr)] strPointerCallback result = null);

        [DllImport("__Internal")]
        public static extern void dbAddDataFloatArray_v2(int pointer, string key, float[] content, int length,
            [MarshalAs(UnmanagedType.FunctionPtr)] strPointerCallback result = null);


        [DllImport("__Internal")]
        public static extern void dbGetData_v2(int pointer, string key,
            [MarshalAs(UnmanagedType.FunctionPtr)] strPointerCallback result);

        [DllImport("__Internal")]
        public static extern void dbGetDataInt_v2(int pointer, string key,
            [MarshalAs(UnmanagedType.FunctionPtr)] intPointerCallback result);

        [DllImport("__Internal")]
        public static extern void dbGetDataFloat_v2(int pointer, string key,
            [MarshalAs(UnmanagedType.FunctionPtr)] floatPointerCallback result);

        [DllImport("__Internal")]
        public static extern void dbGetDataFloatArray_v2(int pointer, string key,
            [MarshalAs(UnmanagedType.FunctionPtr)] floatArrayPointerCallback result);


        [DllImport("__Internal")]
        public static extern void dbDelData_v2(string key);

        [DllImport("__Internal")]
        public static extern void freeFloatArrayMemory(IntPtr key);
/*---------------------------------------- Find the callback function through the pointer ---------------------------------------------------------------------------*/

        public static Dictionary<int, Action<float>> floatDic = new Dictionary<int, Action<float>>();
        public static Dictionary<int, Action<float[]>> floatArrayDic = new Dictionary<int, Action<float[]>>();
        public static Dictionary<int, Action<int>> intDic = new Dictionary<int, Action<int>>();
        public static Dictionary<int, Action<string>> strDic = new Dictionary<int, Action<string>>();
        public static Dictionary<int, Action<bool>> boolDic = new Dictionary<int, Action<bool>>();

        [AOT.MonoPInvokeCallback(typeof(strPointerCallback))]
        public static void ResultStr_SetKey(int pointer, string key)
        {
            if (string.IsNullOrEmpty(key) || key == "null")
            {
                ExecuteBack(boolDic, pointer, false, "ResultStrSet");
            }
            else
            {
                ExecuteBack(boolDic, pointer, true, "ResultStrSet");
            }
        }

        [AOT.MonoPInvokeCallback(typeof(strPointerCallback))]
        public static void ResultStr(int pointer, string value)
        {
            ExecuteBack(strDic, pointer, value, "ResultStr");
        }

        [AOT.MonoPInvokeCallback(typeof(intPointerCallback))]
        public static void ResultInt(int pointer, int value)
        {
            ExecuteBack(intDic, pointer, value, "ResultInt");
        }

        [AOT.MonoPInvokeCallback(typeof(floatPointerCallback))]
        public static void Resultfloat(int pointer, float value)
        {
            ExecuteBack(floatDic, pointer, value, "Resultfloat");
        }


        // [AOT.MonoPInvokeCallback(typeof(floatArrayPointerCallback))]
        // public static void ResultfloatArray(int pointer, float[] value)
        // {
        //     ExecuteBack(floatArrayDic, pointer, value, "ResultfloatArray");
        // }

        [AOT.MonoPInvokeCallback(typeof(floatArrayPointerCallback))]
        public static void ResultfloatArray(int pointer, IntPtr uint8ArrayPointer, int length)
        {
            float[] data2 = new float[length];
            try
            {
                Marshal.Copy(uint8ArrayPointer, data2, 0, length);
            }
            finally
            {
                // 释放内存
                Marshal.FreeHGlobal(uint8ArrayPointer);
            }

            if (floatArrayDic != null && floatArrayDic.TryGetValue(pointer, out var back))
            {
                try
                {
                    back?.Invoke(data2);
                }
                catch (Exception e)
                {
                    Debug.LogError(e.Message);
                }

                floatArrayDic.Remove(pointer);
            }
        }

        static void ExecuteBack<T>(Action<T> back, T value, string msg)
        {
            try
            {
                back?.Invoke(value);
            }
            catch (Exception e)
            {
                //不要改debug,否则找不到错误.
                Debug.LogError($"[IndexDB.{msg}] => {e.Message}");
            }
        }

        static void ExecuteBack<T>(Dictionary<int, Action<T>> dic, int pointer, T _value, string msg)
        {
            if (dic != null && dic.TryGetValue(pointer, out var back))
            {
                ExecuteBack(back, _value, msg);
                dic.Remove(pointer);
            }
        }
    }
}
#endif